#include <memory>
#include <iostream>
#include <functional>
using namespace std;
namespace fuh{
    template<class T>
    class unique_ptr_1{
        public:
        unique_ptr_1(T* p)
        :ptr(p)
        {

        }
        unique_ptr_1(const unique_ptr_1& a) = delete;
        unique_ptr_1 operator=(const unique_ptr_1& a) = delete;
        T& operator*()
        {
            if(ptr)
            {
                return *ptr;
            }
            else
            {
                throw "Ref nullptr";
            }
        }
        T* operator->()
        {
            return ptr;
        }
        ~unique_ptr_1()
        {
            delete[] ptr;
        }
        private:
        T* ptr;
    };
};

int Test_unique_ptr()
{
    //unique_ptr禁止使用构造拷贝构造，C++11里面通过delete关键字，删除对应的函数
    unique_ptr<string> p(new string("hello "));
    fuh::unique_ptr_1<int> p1(new int);
    p->append("Comic\n");
    cout<<(*p);
    return 0;
}


namespace fuh{
    template <class T>
    class sharePtr{
        typedef sharePtr<T> Self;
        T* m_ptr;
        int* count;
        function<void(T*)> _del= [](T*ptr)mutable->void{delete ptr;};//解决申请数组空间释放的问题
        public:
        T* get()
        {
            return m_ptr;
        }
        int Usecount()
        {
            return *count;
        }
        sharePtr(T* p)
        :m_ptr(p)
        ,count(new int(1))
        {
            
        }
        template<class Del>
        sharePtr(T* p,Del del )
        :m_ptr(p)
        ,count(new int(1))
        ,_del(del)
        {
            
        }


        //可以直接写这个含缺省参数取顶替上面两个，这样就不需要在声明那里给默认值
        // template<class Del>
        // sharePtr(T* p,Del del = [](T*ptr)mutable->void{delete ptr;})
        // :m_ptr(p)
        // ,count(new int(1))
        // ,_del(del)
        // {
            
        // }
        sharePtr()
        :m_ptr(nullptr)
        ,count(new int(1))
        {
            
        }
        Self operator=(const Self& ptr)
        {
            if(this ==&ptr)
            {
                return *this;
            }
            release();
            m_ptr = ptr.m_ptr;
            count = ptr.count;
            (*count)++;
            return *this;
        }
        sharePtr(const Self& ptr)
        :m_ptr(ptr.m_ptr)
        ,count(ptr.count)
        {
            if(count && *count>0)
            {
                ++*count;
            }
        }
        T* operator->()
        {
            return m_ptr;
        }
        T& operator*()
        {
            return *m_ptr;
        }
        ~sharePtr()
        {
            release();
        }
        void release()
        {
            if(--*count ==0)
            {
                _del(m_ptr);
                delete count;
                count = nullptr;
                m_ptr = nullptr;
            }
        }
    };
};


int  Test_sharePtr()
{
    fuh::sharePtr<int> p1(new int(1));
    fuh::sharePtr<int> p2(new int(2));
    fuh::sharePtr<int> p3(new int(3));
    fuh::sharePtr<int> p4 = p1;
    fuh::sharePtr<int> p5 = p2;
    fuh::sharePtr<int> p6 =  p3 = p1;
    p2 = p2;
    return 0;
}


//share_ptr的缺陷，没有办法循环引用
struct Node{
    int val;
    fuh::sharePtr<Node>  next;
    fuh::sharePtr<Node>  prev;
    Node(int a = 0)
    :val(a)
    {

    }
    ~Node()
    {
        cout<<"~Node"<<endl;
    }
};

int Test_sharePoint_disadvantage()
{
    fuh::sharePtr<Node> n1(new Node(1));
    fuh::sharePtr<Node> n2(new Node(2));
    n2->prev = n1;//单引用不会存在任何问题，但是如果是下述情况，其存在的问题就大了
    n1->next = n2;
    return 0;
}

//C+=里面提供weak_ptr解决了这个问题
//底层的weakPtr，还有个引用计数，用sharePtr构造的时候，理论也应该搞个计数存一下，这里主要是为了解决循环引用
//不在多言
namespace fuh{
        template<class T>
    class WeakPtr{
        T* m_ptr;
        public:
        typedef WeakPtr<T> Self;
        WeakPtr()
        :m_ptr(nullptr)
        {

        }
        WeakPtr(const sharePtr<T>& p)
        :m_ptr(p.get())
        {

        }
        Self& operator=(sharePtr<T>p)
        {
            m_ptr = p.get();
            return *this;
        }
        T* operator->()
        {
            return m_ptr;
        }
        T& operator*()
        {
            return *m_ptr;
        }
    };  
    struct Node{
        int val;
        fuh::WeakPtr<Node>  next;
        fuh::WeakPtr<Node>  prev;
        Node(int a = 0)
        :val(a)
        {

        }
        ~Node()
        {
            cout<<"~Node"<<endl;
        }
    };
    //weakPtr是不自持RAII的   

    

};

int test_weak_ptr()
{
    //针对这种循环引用的指针，我们就使用weak_ptr就能解决问题
    fuh::sharePtr<fuh::Node> n1(new fuh::Node(1));
    fuh::sharePtr<fuh::Node> n2(new fuh::Node(2));
    n1->next =n2;
    n2->prev = n1;
    return 0;
}


//-------------------------------------------------------
//接下来解决之前残留的智能指针对于开数组释放的问题，其实就是用仿函数取支持


// int main()
// {
//     fuh::sharePtr<fuh::Node> pInt ( new fuh::Node[10],[](fuh::Node*ptr)mutable{delete []ptr;});
//     cout<<endl;
//     fuh::sharePtr<fuh::Node> pInt2 = new fuh::Node;
//     return 0;
// } 


//--------------------------------------
//We can Get Use the sharePtr implement the Use the Based Class Ptr point ths Derived object ,the we can Call the destructor function by the Based Ptr
//The Implement is following


template <class T>
    class sharePtr{
        typedef sharePtr<T> Self;
        T* m_ptr;
        int* count;
        function<void(T*)> _del;
        public:
        T* get()
        {
            return m_ptr;
        }
        int Usecount()
        {
            return *count;
        }

        //用这种初始化构造函数有个好处，就是即是说你是<class A>,也依然会以delete B来默认释放，C++的标准实际也是有如此设计的方案
        //但是依然还是需要定制删除器，来解决数组释放问题
        template<typename T2>
        sharePtr(T2* p)
        :m_ptr(p)
        ,count(new int(1))
        {
            _del = [p](void* ){delete p;};
        }
        //提供定制删除器
        template<typename T2,typename Del>
        sharePtr(T2* p,Del del)
        :m_ptr(p)
        ,_del(del)
        ,count(new int(1))
        {
            
        }
        sharePtr()
        :m_ptr(nullptr)
        ,count(new int(1))
        {
        }
        Self operator=(const Self& ptr)
        {
            if(this ==&ptr)
            {
                return *this;
            }
            release();
            m_ptr = ptr.m_ptr;
            count = ptr.count;
            (*count)++;
            return *this;
        }
        sharePtr(const Self& ptr)
        :m_ptr(ptr.m_ptr)
        ,count(ptr.count)
        {
            if(count && *count>0)
            {
                ++*count;
            }
        }
        T* operator->()
        {
            return m_ptr;
        }
        T& operator*()
        {
            return *m_ptr;
        }
        ~sharePtr()
        {
            release();
        }
        void release()
        {
            if(--*count ==0)
            {
                _del(m_ptr);
                delete count;
                count = nullptr;
                m_ptr = nullptr;
            }
        }
    };


    int main()
    {
        return 0;
    }